package com.chezai.client.global;

import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;

import com.chezai.client.bean.LatLng;
import com.chezai.client.bean.Polygon;
import com.chezai.client.bean.Speech;
import com.chezai.client.server.TerminalSocketClientManager;
import com.chezai.client.utils.SpeechUtils;
import com.google.android.collect.Lists;
import com.jx.driving.request.Terminal0x0704Request;
import com.jx.driving.response.Terminal0x8704Response;
import com.orhanobut.logger.Logger;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.util.ArrayList;
import java.util.List;

/**
 * 围栏管理
 * 1.获取当前设备的围栏
 * 2.判断当前定位是否在围栏内
 * 3.出围栏或进入围栏语音提示
 * Created by likunyang on 2018/1/22.
 */

public class PolygonManager {
    private static PolygonManager instance;
    private static int SPEECH_VIDEO = 0x0011;
    private List<Polygon> polygons = Lists.newArrayList();
    private boolean preIsIn = true;//上一次是否在围栏内，默认值true。可以忽略刚开始练车时就在围栏内的情况
    private Handler handler = new Handler(Looper.getMainLooper(), new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            if (msg.what == SPEECH_VIDEO) {
                playFenceSound((Boolean) msg.obj);
                return true;
            }
            return false;
        }
    });

    private PolygonManager() {
    }

    public static PolygonManager getInstance() {
        if (instance == null) {
            synchronized (PolygonManager.class) {
                if (instance == null) {
                    instance = new PolygonManager();
                }
            }
        }
        return instance;
    }

    //注册围栏数据
    public void registerPolygonEvent() {
        if (!EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().register(this);
        }
    }

    //注销围栏数据
    public void unRegisterPolygonEvent() {
        if (EventBus.getDefault().isRegistered(this)) {
            EventBus.getDefault().unregister(this);
        }
        polygons = Lists.newArrayList();
    }

    @Subscribe(threadMode = ThreadMode.BACKGROUND)
    public void onEventLatLng(LatLng latLng) {
        boolean b = latLngInPolygon(latLng);
        Message message = handler.obtainMessage();
        message.what = SPEECH_VIDEO;
        message.obj = b;
        handler.sendMessage(message);
    }

    @Subscribe
    public void onEventTerminal0x8704(Terminal0x8704Response ox8704) {
        String result = ox8704.getPolygon();
        if (!TextUtils.isEmpty(result)) {
            String[] polygonArr = result.split("&");
            polygons = new ArrayList<>(polygonArr.length);
            for (int i = 0; i < polygonArr.length; i++) {
                String polygon = polygonArr[i];
                if (TextUtils.isEmpty(polygon)) continue;
                String[] points = polygon.split(";");
                Polygon p = new Polygon();
                List<LatLng> latLngs = new ArrayList<>(points.length);
                for (int j = 0; j < points.length; j++) {
                    String[] point = points[j].split(",");
                    LatLng latLng = new LatLng(Double.parseDouble(point[0]), Double.parseDouble(point[1]));
                    latLngs.add(latLng);
                }
                p.setPoints(latLngs);
                polygons.add(p);
            }
            Logger.t("Polygons").i("result: " + result + "polygonArr length is " + polygonArr.length + " polygons size is " + polygons.size());
        }
    }

    /**
     * 获取围栏范围
     * 2：第二部分
     * 3：第三部分
     */
    public void getPolygon(short port) {
        Terminal0x0704Request request = new Terminal0x0704Request();
        request.setSubject(port);
        TerminalSocketClientManager.getInstance().tellWithNeedAuth(request);
    }

    /**
     * 功能：判断点是否在多边形内
     * 方法：求解通过该点的水平线与多边形各边的交点
     * 结论：单边交点为奇数，成立!
     *
     * @param point 指定的某个点
     * @return
     */
    public boolean latLngInPolygon(LatLng point) {
        boolean isIn;
        int nCross = 0;
        if (polygons == null || polygons.size() == 0) return true;
        for (int j = 0; j < polygons.size(); j++) {
            List<LatLng> latLngs = polygons.get(j).getPoints();
            for (int i = 0; i < latLngs.size(); i++) {
                LatLng p1 = latLngs.get(i);
                LatLng p2 = latLngs.get((i + 1) % latLngs.size());
                // 求解 y=p.y 与 p1p2 的交点
                if (p1.getLng() == p2.getLng())      // p1p2 与 y=p0.y平行
                    continue;
                if (point.getLng() < Math.min(p1.getLng(), p2.getLng()))   // 交点在p1p2延长线上
                    continue;
                if (point.getLng() >= Math.max(p1.getLng(), p2.getLng()))   // 交点在p1p2延长线上
                    continue;
                // 求交点的 X 坐标 --------------------------------------------------------------
                double x = (point.getLng() - p1.getLng())
                        * (p2.getLat() - p1.getLat())
                        / (p2.getLng() - p1.getLng())
                        + p1.getLat();
                if (x > point.getLat())
                    nCross++; // 只统计单边交点
            }
            // 单边交点为偶数，点在多边形之外 ---
            isIn = nCross % 2 == 1;
            if (isIn) {
                return true;
            }
        }
        return false;
    }

    /**
     * 播放进出围栏提示语
     * 1.出围栏，并且未播放过，出围栏则播放出围栏提示音
     * 2.进围栏，并且执行1中情况，进围栏则播放近围栏提示音
     *
     * @param isIn true 围栏内，false 围栏外
     */
    public void playFenceSound(boolean isIn) {
        if (preIsIn == isIn) return;
        preIsIn = isIn;
        if (isIn) {
            SpeechUtils.getInstance().playOrComposed(Speech.POLYGON_IN.getMsg(), Speech.POLYGON_IN.getFilePath());
        } else {
            SpeechUtils.getInstance().playOrComposed(Speech.POLYGON_OUT.getMsg(), Speech.POLYGON_OUT.getFilePath());
        }
    }
}
